﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading;

namespace Twi.DataAccess.Common
{
    /*
     * CopyRight:©2013 踏影软件（Tyingsoft）开发工作室版权所有
     * Author:xuzhihong
     * Create Date: 2013-08-07
     * Description: 最大记录编号（值）对象
     */

    /// <summary>
    /// 最大记录编号（值）对象
    /// </summary>
    public class DBMaxCode
    {
        public DBMaxCode()
        {
            TableName = "TMAXRECORD";
            SignField = "FNAME";
            ValueField = "FMAXVALUE";
            Increase = 1;
            UniqueCodeField = "FUNIQUECODE";
        }

        public DbUtility DB
        {
            get;
            set;
        }

        /// <summary>
        /// 存储最大记录编号的表名
        /// </summary>
        public string TableName
        {
            get;
            set;
        }

        /// <summary>
        /// 标识字段名
        /// </summary>
        public string SignField
        {
            get;
            set;
        }

        /// <summary>
        /// 最大记录编号值的字段名
        /// </summary>
        public string ValueField
        {
            get;
            set;
        }

        /// <summary>
        /// 每次取完值后的增加量（增长量、步长）
        /// </summary>
        public int Increase
        {
            get;
            set;
        }

        /// <summary>
        /// 唯一编码（GUID），为解决并发问题使用
        /// </summary>
        public string UniqueCodeField
        {
            get;
            set;
        }

        /*
        /// <summary>
        /// 获取当前最大值的SQL语句
        /// </summary>
        /// <param name="signFieldValue">标识字段的值</param>
        /// <param name="newIncrease">0:表示使用默认的DBMaxCode.Increase增长量（步长）</param>
        /// <returns></returns>
        public int GetNextValue(string signFieldValue,int newIncrease=0)
        {
            //最后实际使用的增长量
            int lastIncrease = newIncrease > 1 ? newIncrease : Increase;
            lastIncrease = lastIncrease < 1 ? 1 : lastIncrease; //如果设置的默认增加量小于1，设置为1

            string strSql = string.Format("select {0} from {1} where {2}='{3}'",ValueField, TableName, SignField, signFieldValue);
            object obj = DB.ExecuteScalar(strSql);
            int maxValue = 0;
            if (obj == null) //如果数据库没有，则自动新增一条记录
            {
                strSql = string.Format("insert into {0}({1},{2}) values('{3}','{4}')", TableName, SignField, ValueField, signFieldValue,lastIncrease);
                DB.ExecuteNonQuery(strSql);
            }
            else
            {
                maxValue = Convert.ToInt32(obj);
                //自动加Increase
                strSql = string.Format("update {0} set {1}={1}+{2} where {3}='{4}'", TableName, ValueField, lastIncrease, SignField, signFieldValue);
                DB.ExecuteNonQuery(strSql);
            }

            return maxValue + lastIncrease;
        }
        */

        /// <summary>
        /// 获取当前最大值的SQL语句
        /// </summary>
        /// <param name="signFieldValue">标识字段的值</param>
        /// <param name="newIncrease">0:表示使用默认的DBMaxCode.Increase增长量（步长）</param>
        /// <returns></returns>
        public int GetNextValue(string signFieldValue, int newIncrease = 0)
        {
            int maxValue = TryGetNextValue(signFieldValue,newIncrease);
            if (maxValue == -1)
            {
                Thread.Sleep(200);                
                maxValue = TryGetNextValue(signFieldValue, newIncrease);
            }
            if (maxValue == -1)
            {
                Thread.Sleep(200);
                maxValue = TryGetNextValue(signFieldValue, newIncrease);
            }
            if (maxValue == -1)
            {
                throw new Exception("最大记录编号尝试获取三次后失败！");
            }
            return maxValue;
        }

        /// <summary>
        /// 尝试获取当前最大值[可能不对，会返回-1]
        /// </summary>
        /// <param name="signFieldValue">标识字段的值</param>
        /// <param name="newIncrease">0:表示使用默认的DBMaxCode.Increase增长量（步长）</param>
        /// <returns>-1表示需要重新获取</returns>
        private int TryGetNextValue(string signFieldValue, int newIncrease)
        {
            //为了兼容之前的配置，才如此处理
            UniqueCodeField = TableName == "TMAXRECORD" ? "FUNIQUECODE" : "REMARK";

            //最后实际使用的增长量
            int lastIncrease = newIncrease > 1 ? newIncrease : Increase;
            lastIncrease = lastIncrease < 1 ? 1 : lastIncrease; //如果设置的默认增加量小于1，设置为1
            int maxValue = 0;
            Action<DbCommand> action = (DbCommand command) =>
            {
                string strSql = string.Format("select {0},{1} from {2} where {3}='{4}'", ValueField, UniqueCodeField, TableName, SignField, signFieldValue);
                command.CommandText = strSql;
                DataTable dt = command.ExecuteDataTable(DB);

                if (dt.Rows.Count == 0) //如果数据库没有，则自动新增一条记录
                {
                    strSql = string.Format("insert into {0}({1},{2},{3}) values('{4}','{5}','{6}')", TableName, SignField, ValueField, UniqueCodeField, signFieldValue, lastIncrease, Guid.NewGuid().ToString());
                    command.CommandText = strSql;
                    command.ExecuteNonQuery();
                }
                else
                {
                    maxValue = Convert.ToInt32(dt.Rows[0][ValueField]);
                    string uniqueCode = "" + dt.Rows[0][UniqueCodeField];
                    //自动加Increase
                    if (uniqueCode != "")
                    {
                        strSql = string.Format("update {0} set {1}={1}+{2},{3}='{4}' where {5}='{6}' and {7}='{8}'",
                            TableName, ValueField, lastIncrease, UniqueCodeField, Guid.NewGuid(), SignField, signFieldValue, UniqueCodeField, uniqueCode);
                    }
                    else
                    {
                        strSql = string.Format("update {0} set {1}={1}+{2},{3}='{4}' where {5}='{6}'",
                            TableName, ValueField, lastIncrease, UniqueCodeField, Guid.NewGuid(), SignField, signFieldValue);
                    }
                    command.CommandText = strSql;
                    int count = command.ExecuteNonQuery();
                    if (count == 0) //受影响行数为0
                    {
                        maxValue = -1;//表示，为过期数据，需要重新获取
                    }
                    else
                    {
                        maxValue = maxValue + lastIncrease;
                    }
                }
            };

            DB.ExecuteTransaction(action);
            return maxValue;
        }
    }
}
